﻿using System;
using System.Collections.Generic;


namespace MashGen.Engine.Expressions
{
    public class Sum : AbstractExpression
    {
        public IList<AbstractExpression> Summands { get; private set; }

        private IList<AbstractExpression> normalizedSummands;

        internal IList<AbstractExpression> NormalizedSummands
        {
            get
            {
                if (normalizedSummands == null)
                {
                    normalizedSummands = Normalizer.NormalizeSummands(Summands);
                }
                return normalizedSummands;
            }   
        }
        
        public Sum(List<AbstractExpression> summands)
        {
            if (summands == null)
            {
                throw new ArgumentNullException("summands");
            }
            if (summands.Count < 2)
            {
                throw new ArgumentException("Sum needs at least two summands.", "summands");
            }
            foreach (var summand in summands)
            {
                if (summand == null)
                {
                    throw new ArgumentNullException("summand");
                }
            }
            Summands = summands.AsReadOnly();
        }

        public Sum(params AbstractExpression[] summands)
            : this(new List<AbstractExpression>(summands))
        {
        }

        public override R Vist<R, P>(IExpressionVisitor<R, P> visitor, P parameter = default(P))
        {
            return visitor.VisitSum(this, parameter);
        }

        public override bool Equals(AbstractExpression other)
        {
            var otherSum = other as Sum;
            if (ReferenceEquals(otherSum, null))
            {
                return false;
            }

            if (this.Summands.Count != otherSum.Summands.Count)
            {
                return false;
            }

            for (int index = 0; index < Summands.Count; index++)
            {
                if (!this.NormalizedSummands[index].Equals(otherSum.NormalizedSummands[index]))
                {
                    return false;
                }
            }
            return true;
        }

        public override int GetHashCode()
        {
            int hashCode = 0;
            foreach (var summand in Summands)
            {
                hashCode ^= summand.GetHashCode();
            }
            return 2 * hashCode;
        }
    }
}
